#include "StdAfx.h"
#include "ylGroupTreeView.h"
#include "ylSessionData.h"
#include "ylNodeUtils.h"
#include "ylLogMessageGroup.h"
#include "ylLogMessageClass.h"

using namespace yoctolog_viewer;


TreeNode ^GroupTreeView::CreateOrGetNode( String ^strNode )
{
	strNode = strNode->Replace("\\", "/");
	array<String^> ^vecTagTree = (strNode)->Split((gcnew String("/"))->ToCharArray());

	TreeNodeCollection ^pCurrentNodeCollection = Nodes;
	TreeNode ^pNode = nullptr;
	for( int i = 0; i < vecTagTree->Length; i++ )
	{
		System::String ^strCurrentTag = vecTagTree[i];
		System::Windows::Forms::TreeNode ^ pFoundNode = FindNode(strCurrentTag, pCurrentNodeCollection);
		if( !pFoundNode )
		{
			pNode = pCurrentNodeCollection->Add(strCurrentTag, strCurrentTag);
		}
		else
		{
			pNode = pFoundNode;
		}
		pCurrentNodeCollection = pNode->Nodes;
	}

	return pNode;
}


System::Void GroupTreeView::OnAfterSelect( System::Object^ sender, System::Windows::Forms::TreeViewEventArgs^ e )
{
	if( e->Node )
	{
		LogMessageGroup ^pSelectedGroup = nullptr;

		System::String ^strNodePath = GetNodePath(e->Node);
		if( m_pSessionData->m_mapGroups->ContainsKey(strNodePath) )
		{
			pSelectedGroup = m_pSessionData->m_mapGroups[strNodePath];
		}

		if( GroupSelected )
		{
			GroupSelected(pSelectedGroup);
		}
	}
}


void GroupTreeView::UpdateGroups()
{
	BeginUpdate();
	for each( System::Collections::Generic::KeyValuePair<System::String ^, LogMessageGroup ^> kv in m_pSessionData->m_mapGroups )
	{
		TreeNode ^pTreeNode = CreateOrGetNode(kv.Key);
		pTreeNode->Tag = kv.Value;
		pTreeNode->Text = pTreeNode->Name;
	}
	EndUpdate();
}


void GroupTreeView::OnMouseDown( Object^ /*sender*/, MouseEventArgs^ e )
{
	TreeNode^ pClickedNode = GetNodeAt( e->X, e->Y );
	if ( pClickedNode && NodeBounds( pClickedNode ).Contains( e->X, e->Y ) )
	{
		SelectedNode = pClickedNode;
	}
}


void GroupTreeView::OnDrawNode( Object^ sender, DrawTreeNodeEventArgs^ e )
{
	e->DrawDefault = true;

	Rectangle xNodeRect = e->Bounds;

	int iStartX = xNodeRect.Right + 10;
	int iStartY = xNodeRect.Top;
	int iBoxSize = 10;

	// Clear the node area
	e->Graphics->FillRectangle( Brushes::White, NodeBounds( e->Node ) );

	// Retrieve the node font. If the node font has not been set,
	// use the TreeView font.
	System::Drawing::Font^ pNodeFont = e->Node->NodeFont;
	if ( pNodeFont == nullptr )
		pNodeFont = Font;

	LogMessageGroup ^pGroup = (LogMessageGroup^)e->Node->Tag;

	if( !pGroup )
		return;

	for each( System::Collections::Generic::KeyValuePair<unsigned char, LogMessageClass ^> kv in m_pSessionData->m_mapMessageClasses )
	{
		if( !kv.Value )
			continue;

		if( pGroup->m_mapClassCounts.ContainsKey(kv.Value) )
		{
			unsigned int uiGroupCount = pGroup->m_mapClassCounts[kv.Value];
			String ^strText = Int32(uiGroupCount).ToString();
			System::Drawing::SizeF xTextExtents = e->Graphics->MeasureString(strText, pNodeFont);

			if( kv.Value->m_bgColor )
				e->Graphics->FillRectangle( gcnew SolidBrush(*kv.Value->m_bgColor), iStartX - iBoxSize, iStartY, (int)xTextExtents.Width, (int)xTextExtents.Height);

			e->Graphics->DrawString(strText, pNodeFont, gcnew SolidBrush(*kv.Value->m_textColor), float(iStartX - iBoxSize), float(iStartY));
			iStartX += int(xTextExtents.Width);
		}
	}
}


Rectangle GroupTreeView::NodeBounds( TreeNode^ pNode )
{
	// Set the return value to the normal node bounds.
	Rectangle bounds = pNode->Bounds;
	if ( pNode->Tag != nullptr )
	{
		System::Drawing::Font^ pNodeFont = pNode->NodeFont;
		if ( pNodeFont == nullptr )
			pNodeFont = Font;

		// Retrieve a Graphics object from the TreeView handle
		// and use it to calculate the display width of the tag.
		Graphics^ g = CreateGraphics();
		int iWidth = 0;

		LogMessageGroup ^pGroup = (LogMessageGroup^)pNode->Tag;

		if( !pGroup )
			return bounds;

		for each( System::Collections::Generic::KeyValuePair<unsigned char, LogMessageClass ^> kv in m_pSessionData->m_mapMessageClasses )
		{
			if( !kv.Value )
				continue;

			if( pGroup->m_mapClassCounts.ContainsKey(kv.Value) )
			{
				unsigned int uiGroupCount = pGroup->m_mapClassCounts[kv.Value];
				String ^strText = Int32(uiGroupCount).ToString();
				iWidth += (int)g->MeasureString( strText, pNodeFont ).Width;
			}
		}

		// Adjust the node bounds using the calculated value.
		bounds.Offset( iWidth / 2, 0 );
		bounds = Rectangle::Inflate( bounds, iWidth / 2, 0 );
		g->~Graphics();
	}

	return bounds;
}
